package controllers;

import geo.google.GeoException;
import geo.google.datamodel.GeoCoordinate;

import java.util.List;

import models.Category;
import models.Deal;
import models.District;
import play.data.validation.Valid;
import play.db.jpa.Transactional;
import play.i18n.Messages;
import play.mvc.Before;
import utils.GeoAddressUtil;

/**
 * This class handles deal administration
 * 
 */
public class DealsAdmin extends Application {

	/**
	 * For every method run in this class, check if the user is logged in, if
	 * not, redirect the user to the login page
	 */
	@Before
	static void checkUser() {
		if (connected() == null) {
			flash.error("Please log in first");
			Application.index();
		}
	}

	/**
	 * Delete deal by id
	 * 
	 * @param id
	 *            The deal id
	 */
	public static void deleteDeal(Long id) {
		Deal deal = Deal.findById(id);
		deal.delete();
		flash.success(deal.title + " has been deleted successfully.");
		index();
	}

	/**
	 * Edit the deal given the deal id
	 * 
	 * @param id
	 *            The deal id
	 */
	public static void editDeal(Long id) {
		List<Category> categories = Category.findAll();
		List<District> districts = District.findAll();
		Deal deal = Deal.findById(id);
		render(deal, categories, districts);
	}

	/**
	 * Update the deal (POST method for edit deal form)
	 * 
	 * @param id
	 *            The deal id
	 * @param deal
	 *            The deal itself
	 * @throws GeoException
	 */
	public static void updateDeal(Long id, @Valid Deal deal) throws GeoException {
		validation.required(deal.address);
		
		// end date should come after start date
		if (deal.endDate.before(deal.startDate)) {
			validation.addError("deal.endDate", "validation.deal.endDateError", "test");
		}
		if (deal.discountPrice.compareTo(deal.oldPrice) > 0) {
			validation.addError("deal.discountPrice", "validation.deal.price", "test");
		}

		
		deal.user = connected();

		GeoCoordinate coordinate = null;
		try {
			// get the deal location
			coordinate = GeoAddressUtil.getGeoCoordinates(deal.address);
		} catch (Exception e) {
			validation.addError("deal.address.city", "deal.address.error", "test");
			List<Category> categories = Category.findAll();
			List<District> districts = District.findAll();
			deal.id = id;
			render("@editDeal", deal, categories, districts);
		}

		if (null != coordinate) {
			deal.latitude = coordinate.getLatitude();
			deal.longitude = coordinate.getLongitude();
		}

		if (validation.hasErrors()) {
			List<Category> categories = Category.findAll();
			List<District> districts = District.findAll();
			deal.id = id;
			render("@editDeal", deal, categories, districts);
		}

		Deal deal_old = Deal.findById(id);

		// The following looks extremely redundant/complicated but it is the
		// only
		// way I have identified to achieve an actual update
		// (as opposed to a second record being persisted in the database)
		// -> comments welcome
		deal_old.title = deal.title;
		deal_old.description = deal.description;
		deal_old.oldPrice = deal.oldPrice;
		deal_old.discountPrice = deal.discountPrice;
		deal_old.startDate = deal.startDate;
		deal_old.endDate = deal.endDate;
		if (null != deal.photo) {
			deal_old.photo = deal.photo;
		}
		deal_old.latitude = deal.latitude;
		deal_old.longitude = deal.longitude;
		deal_old.address = deal.address;
		deal_old.category = deal.category;
		deal_old.district = deal.district;

		deal_old.save();

		flash.success(Messages.get("deal.updated.text", deal.title));
		DealsAdmin.index();
	}

	/**
	 * Deal admin main page where we display the deals created by the logged in
	 * user
	 */
	public static void index() {
		List<Deal> myDeals = Deal.find("byUser", connected()).fetch();
		render(myDeals);
	}

	/**
	 * Create new deal
	 */
	public static void newDeal() {
		List<Category> categories = Category.findAll();
		List<District> districts = District.findAll();
		render(categories, districts);
	}

	/**
	 * Save deal (POST method for the create new deal form)
	 * 
	 * @param deal
	 * @throws GeoException
	 */
	@Transactional
	public static void saveDeal(@Valid Deal deal) {
		validation.required(deal.address);
		
		// end date should come after start date
		if (deal.endDate.before(deal.startDate)) {
			validation.addError("deal.endDate", "validation.deal.endDateError", "test");
		}

		if (deal.discountPrice.compareTo(deal.oldPrice) > 0) {
			validation.addError("deal.discountPrice", "validation.deal.price", "test");
		}

		deal.user = connected();

		GeoCoordinate coordinate = null;
		try {
			// get the deal location
			coordinate = GeoAddressUtil.getGeoCoordinates(deal.address);
		} catch (Exception e) {
			validation.addError("deal.address.city", "deal.address.error", "test");
			List<Category> categories = Category.findAll();
			List<District> districts = District.findAll();
			render("@newDeal", deal, categories, districts);
		}

		if (validation.hasErrors()) {
			List<Category> categories = Category.findAll();
			List<District> districts = District.findAll();
			render("@newDeal", deal, categories, districts);
		}

		if (null != coordinate) {
			deal.latitude = coordinate.getLatitude();
			deal.longitude = coordinate.getLongitude();
		}
		deal.create();
		DealsAdmin.index();
	}
}
